﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using SpectationClient.DataBaseDescription;
using SpectationClient.Stuff;
using GeoAPI.Geometries;
namespace SpectationClient.SQLCommandBuilder {
    
    public partial class UC_SetCondition: UserControl {
        ErrorList EL = new ErrorList();
        TableInfo ti;
        DataSet Constraints = new DataSet();
        Dictionary<String, List<String>> columnOperatorNames = new Dictionary<String, List<String>>();
        Dictionary<String, Dictionary<String, GeometricCondition.Op>> OP_Geometry = new Dictionary<string, Dictionary<String, GeometricCondition.Op>>();
        Dictionary<String, Dictionary<String, Condition.Op>> OP = new Dictionary<string, Dictionary<String, Condition.Op>>();

        public UC_SetCondition() {
            InitializeComponent();

            this.init();
        }

        public UC_SetCondition(TableInfo ti) {
            this.ti = ti;

            this.init();
        }

        public TableInfo TableInfo {
            get { return this.ti; }
            set { this.ti = value; this.refreshTableInfo(); }
        }

        private void init() {
          

            this.DGV.RowsAdded += new DataGridViewRowsAddedEventHandler(DGV_RowsAdded);
            this.DGV.RowsRemoved += new DataGridViewRowsRemovedEventHandler(DGV_RowsRemoved);
            this.DGV.CellValueChanged += new DataGridViewCellEventHandler(DGV_CellValueChanged);
            
            //this.DGV.CellFormatting += new DataGridViewCellFormattingEventHandler(DGV_CellFormatting);
            this.DGV.DataError += new DataGridViewDataErrorEventHandler(DGV_DataError);
           
            this.refreshTableInfo();
        }

        void DGV_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
          
            DataGridViewRow row = DGV.Rows[e.RowIndex];
            DataGridViewComboBoxCell cbCellColumnName = (DataGridViewComboBoxCell)row.Cells[0];
            DataGridViewComboBoxCell cbCellOperator = (DataGridViewComboBoxCell)row.Cells[1];
            DataGridViewTextBoxCell tbCellValue = (DataGridViewTextBoxCell)row.Cells[2];

            if(e.ColumnIndex == 0) { //change of column name
                String columnName = (String) row.Cells[e.ColumnIndex].Value;
                cbCellOperator.Value = DBNull.Value;
                cbCellOperator.Items.Clear();
                foreach(DataRow r in Constraints.Tables[columnName].Rows){
                    cbCellOperator.Items.Add(r["OPNAME"]);
                }
            }

            if(e.ColumnIndex == 1) { //Operator change

                validateRow(row);
            }
            
            if(e.ColumnIndex == 2) { //Value changed

                validateRow(row);
            }
        }

        private void validateRow(int rowIndex) {
            this.validateRow(DGV.Rows[rowIndex]);
        }

        private void validateRow(DataGridViewRow row) {
            DataGridViewComboBoxCell cbCellColumnName = (DataGridViewComboBoxCell)row.Cells[0];
            DataGridViewComboBoxCell cbCellOperator = (DataGridViewComboBoxCell)row.Cells[1];
            DataGridViewTextBoxCell tbCellValue = (DataGridViewTextBoxCell)row.Cells[2];
            
            if(tbCellValue.Value == DBNull.Value) {
                EL.removeError(tbCellValue);
            } else {

                if(cbCellColumnName.Value == null || ((string)cbCellColumnName.Value) == String.Empty) {
                    EL.addError(tbCellValue, "Keine Datenbankspalte angegeben. ");
                    return;
                }

                if(cbCellOperator.Value == null || cbCellOperator.Value == DBNull.Value || ((string)cbCellOperator.Value) == String.Empty) {
                    EL.addError(tbCellValue, "Kein Operator angegeben.");
                    return;
                }
                
                String valueText = tbCellValue.Value.ToString().Trim();
                String operatorText = cbCellOperator.Value.ToString();
                String columnName = cbCellColumnName.Value.ToString();
                DataTable operatorTable = this.Constraints.Tables[columnName];

                ColumnInfo ci = ti[columnName];
                ColumnInfoGeometry gci = ci as ColumnInfoGeometry;
                if(DataHelper.hasValue(operatorTable.Columns["OPNAME"], operatorText)){
                    Object op = DataHelper.getKeyValue(operatorTable, operatorText, "OPNAME", "OP");
                    if(op is GeometricCondition.Op) {
                        GeometricCondition cond = new GeometricCondition(
                            (ColumnInfoGeometry)this.ti[columnName], (GeometricCondition.Op) op);
                      
                        EL.validation_checkGeometryWKT(tbCellValue, true, gci.GeometryType);



                    } else {
                        EL.validation_checkType(tbCellValue, true, ci.ValueType);
                    }
                }else{
                    //String temp = "";
                }

            }
        }

        void DGV_DataError(object sender, DataGridViewDataErrorEventArgs e) {
         
                throw new NotImplementedException();
        }


        void DGV_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e) {
            
        }

        void DGV_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) {
           
        }

       
        private void refreshTableInfo() {
            
            this.DGV.Rows.Clear();
            this.cColumnName.Items.Clear();
            this.cOperator.Items.Clear();
            this.Constraints.Clear();

            if(this.ti != null) {
                foreach(ColumnInfo ci in this.ti.Values) {
                    this.cColumnName.Items.Add(ci.Name);

                    
                    if(ci is ColumnInfoGeometry) {
                        ColumnInfoGeometry gci = (ColumnInfoGeometry)ci;
                        this.Constraints.Tables.Add(this.getGeometryOperatorsTable(gci.Name, gci.GeometryType));
                    } else {
                        this.Constraints.Tables.Add(this.getOperatorsTable(ci.Name, ci.ValueType));
                    }
                    
                }
            }


        }
        /*
        void cbColumn_SelectedValueChanged(object sender, EventArgs e) {
            ColumnInfo ci = cbColumn.SelectedItem as ColumnInfo;
            ColumnInfoGeometry gci = cbColumn.SelectedItem as ColumnInfoGeometry;
            FileColumnInfo fci = cbColumn.SelectedItem as FileColumnInfo;

            this.FLP.Controls.Clear();
            this.tbPreview.Clear();
            this.lastColumn = null;

            if(fci != null) { 
            
            }
            if(gci != null) {
                this.lastColumn = gci;
                Dictionary<String, GeometricCondition.Op> ops = this.getGeometryColumnTypeOperators(gci.GeometryType);
                foreach(String optext in ops.Keys) {
                    Button b = new Button();
                    b.Text = optext;
                    b.Font = new Font(FontFamily.GenericMonospace, (float)8.25, FontStyle.Regular);
                    b.Tag = ops[optext];
                    b.Width = (int)(optext.Length * b.Font.Size + 20);
                    b.Click += new EventHandler(b_Click);
                    this.FLP.Controls.Add(b);
                }

                return;
            }

            if(ci != null) {
                this.lastColumn = ci;
                Dictionary<String, Condition.Op> ops = this.getColumnTypeOperators(ci.ValueType);

                foreach(String optext in ops.Keys) {
                    Button b = new Button();
                    b.Text = optext;
                    b.Font = new Font(FontFamily.GenericMonospace, (float)8.25, FontStyle.Regular);
                    b.Tag = ops[optext];
                    b.Width = (int)(optext.Length * b.Font.Size + 20);
                    b.Click += new EventHandler(b_Click);
                    this.FLP.Controls.Add(b);
                }
                return;
            }
            
        }
        */
        
        /*
        private AbstractCondition getCondition() {
            
            String text = tbValue.Text.Trim();
            if (lastButton is Button && text.Length > 0 && lastColumn != null){


                if(lastButton.Tag is Condition.Op) {
                    Condition.Op op = (Condition.Op) lastButton.Tag;
                    ColumnInfo ci = lastColumn;
                    EL.validation_checkType(tbValue, true, ci.ValueType);
                    if(EL.isEmpty) {
                        Condition cond = null;
                        if(op == Condition.Op.IS_NULL) {
                            cond = new Condition(ci.Name, !cbNegation.Checked);
                        } else {
                            cond = new Condition(ci.Name, !cbNegation.Checked, op, Convert.ChangeType(text, ci.ValueType));
                        }

                        return cond;
                    }
                }

                if(lastButton.Tag is GeometricCondition.Op) {
                    GeometricCondition.Op gop = (GeometricCondition.Op)lastButton.Tag;
                    ColumnInfoGeometry gci = (ColumnInfoGeometry) lastColumn;

                    EL.validation_checkGeometryWKT(this.tbValue, true, gci.GeometryType);
                    if(EL.isEmpty) {
                        SharpMap.Geometries.Geometry geom = SharpMap.Geometries.Geometry.GeomFromText(this.tbValue.Text);
                        GeometricCondition gcond = new GeometricCondition(gci, gop, cbNegation.Checked);
                        gcond.Add(geom, gci.columnSRID);
                        return gcond;
                    }
                }
            }
            return null;
            

        }
         */
        private void getPreview() {
            
             
        }

        private DataTable getGeometryOperatorsTable(String tablename, OgcGeometryType geometryType) {
            DataTable dt = new DataTable(tablename);
            dt.Columns.Add("OPNAME", typeof(String));
            dt.Columns.Add("OP", typeof(GeometricCondition.Op));
            dt.Rows.Add("is null", GeometricCondition.Op.IS_NULL);
            dt.Rows.Add("is simple", GeometricCondition.Op.IS_SIMPLE);
            return dt;
        }
        
        private DataTable getOperatorsTable(String tableName, Type columnType) {
            DataTable dt = new DataTable(tableName);
            dt.Columns.Add("OPNAME", typeof(String));
            dt.Columns.Add("OP", typeof(Condition.Op));
            dt.Rows.Add("=", Condition.Op.EQ);
            dt.Rows.Add("!=", Condition.Op.NE);
            dt.Rows.Add("is null", Condition.Op.IS_NULL);
            
            if(columnType == typeof(String)) {
                dt.Rows.Add("Like", Condition.Op.LIKE);
                dt.Rows.Add("ILike", Condition.Op.LIKE_CaseInsensitive);
                dt.Rows.Add("Matches", Condition.Op.MATCHES);
                dt.Rows.Add("IMatches", Condition.Op.MATCHES_CaseInsensitive);
            }

            if(columnType.BaseType == typeof(ValueType)) {
                dt.Rows.Add("<", Condition.Op.LT);
                dt.Rows.Add(">", Condition.Op.GT);
                dt.Rows.Add("<=", Condition.Op.LE);
                dt.Rows.Add(">=", Condition.Op.GE);
            }

            return dt;
        }

        
        private void btAdd_Click(object sender, EventArgs e) {
            this.DGV.Rows.Add();
        }

        private void btRemove_Click(object sender, EventArgs e) {
            List<DataGridViewRow> rows = new List<DataGridViewRow>();
            foreach(DataGridViewRow row in this.DGV.Rows) {
                if(row.Selected) rows.Add(row);
            }
            foreach(DataGridViewRow row in rows) {
                this.DGV.Rows.Remove(row);
            }
        }

        private void btClear_Click(object sender, EventArgs e) {
            this.DGV.Rows.Clear();
        }
    }
}
